iT邦幫忙

2022 iThome 鐵人賽

DAY 26
2

前言

嗨,我是Hogan
目前在經營自己的自媒體 hogan.tech
主要分享一些有關於程式碼、軟體和科技業經驗分享
有興趣的讀者可以進一步關注我,進而獲得更多資訊唷!

未來文章一併更新於此網站 Hogan.B Lab
並且包含多語系 繁體中文英文日文簡體中文
觀看分類:React 白話文運動其他系列

如果想要快速查找其他文章請點選目錄

成立 hogan.tech 的初衷是
希望每個正在這條路上探索的人,
都可以透過 Hogan.tech 嘗試進入程式領域。


前一篇會介紹另一種狀態管理- Zustand

  1. 為什麼會想要分享這個技術?
  2. 關於狀態管理
  3. Zustand 是什麼?

這一篇會繼續講解 Zustand

  1. Zustand用法
  2. Zustand是否能超越Context以及Redux

Zustand用法

下面兩個簡單的用法,是針對JavaScript的使用者。

建立第一個Store

Zustand是基於Hook建立的,因此第一個建立的就是由Custom Hook建立的Store裡面可以放入包含變數、物件、函數。並且可以透過Set、Get來去做資料的「狀態管理」

import create from 'zustand'

const useBearStore = create((set) => ({
  bears: 0,
  increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
  removeAllBears: () => set({ bears: 0 }),
}))

針對元件進行綁定

因為是使用Hook,因此在任何元件中皆可以直接載入做使用。也可以針對這些狀態進行渲染,可以看到短短的幾行就可以處理完成,算是Zustand中的一大福音。

function BearCounter() {
  const bears = useBearStore((state) => state.bears)
  return <h1>{bears} around here ...</h1>
}

function Controls() {
  const increasePopulation = useBearStore((state) => state.increasePopulation)
  return <button onClick={increasePopulation}>one up</button>
}

這邊也針對TypeScript使用者提供簡單的Zustand範例

Zustand TypeScript 寫法

在Zustand 我們會使用create來去建立新的store。透過函數傳入,透過Hook來回傳狀態,並且進行再次渲染。

import create from "zustand"

type Product = { sku: string; name: string; image: string }

type CartState = {
  products: Product[]
  cart: { [sku: string]: number }
  addToCart: (sku: string) => void
  removeFromCart: (sku: string) => void
}

// Selectors
// ...

// Initialize our store with initial values and actions to mutate the state
export const useCart = create<CartState>(set => ({
  products: [
    // ...
  ],
  cart: {},
  // Actions
  // ...
}))

這邊也另外展示Redux以及Mobx的寫法,讀者也可以比較其差異,不過這篇不會針對Redux或是Mobx進行講解,只會針對Zustand以及其狀態管理進行講解

Redux TypeScript 寫法

import { createSlice, configureStore, PayloadAction } from "@reduxjs/toolkit"
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux"

// Slices
// Definee the shape of the state and how to mutate it
type ICart = { [sku: string]: number }
const cartInitialState: ICart = {}
const cartSlice = createSlice({
  name: "cart",
  initialState: cartInitialState,
  reducers: {
    // ...
  },
})

type IProduct = { sku: string; name: string; image: string }
const productsInitialState: IProduct[] = [
  // ...
]
const productsSlice = createSlice({
  name: "products",
  initialState: productsInitialState,
  reducers: {},
})

// Actions
// ...

// Selectors
// ...

// Store
export const store = configureStore({
  reducer: {
    cart: cartSlice.reducer,
    products: productsSlice.reducer,
  },
})

// ...
const App = () => {
  return (
    <Provider store={store}>
      <NavigationContainer>
        <Stack.Navigator>{/* ... */}</Stack.Navigator>
        <StatusBar style="auto" />
      </NavigationContainer>
    </Provider>
  )
}

Mobx TypeScript寫法

import { types, Instance } from "mobx-state-tree"

const Product = types.model({
  sku: types.string,
  name: types.string,
  image: types.string,
})

// Model and type our data with mobx state tree
const CartStore = types
  .model("CartStore", {
    products: types.array(Product),
    cart: types.map(types.number),
  })
  // Actions to mutate the state
  .actions(store => ({
    // ...
  }))
  // Views are like selectors
  .views(self => ({
    // ...
  }))

type CartStoreType = Instance<typeof CartStore>

// Spin up a hook to use our store and provide initial values to it
let _cartStore: CartStoreType
export const useCart = () => {
  if (!_cartStore) {
    _cartStore = CartStore.create({
      products: [
        // ...
      ],
      cart: {},
    })
  }

  return _cartStore
}

Zustand是否能超越Context以及Redux呢?

image

https://github.com/pmndrs/zustand#why-zustand-over-redux

根據Zustand官方,列舉以上幾點,這邊也簡單講解一下

Redux本身是一個較為複雜的狀態管理工具,會有Actioins、View、State的流程

以下是Redux的官方資料流示意圖,也可以知道如果要從無到有使用Redux的狀態管理工具學習門檻是比較高的。

image

https://dev.to/oahehc/redux-data-flow-and-react-component-life-cycle-11n

Context 本身雖然是歸類在狀態管理,但實際上比較像是一個集中式觸發狀態的方式。

比起Zustand而言是會發散在各個檔案,不好進行管理。

image

https://dev-yakuza.posstree.com/en/react/context-api/


結語

使用這個技術的優勢

透過Zustand,將複雜的商業邏輯中的,資料以及邏輯拆開,並且針對這些東西去做模組化。除了增加可讀性之外,也讓測試更容易去撰寫。

自身感想?

Zustand本身是一個滿容易學習的狀態管理工具,且自己在工作產品使用上也是相對方便的,包含針對狀態進行Set、Get或是在元件中進行使用都是相對方便,滿推薦給想針對React進行狀態管理的讀者。

如果有任何建議與疑問也歡迎留言!

如果喜歡此系列文章,請不吝於按下喜歡及分享,讓更多人看到唷~


上一篇
React白話文運動25-Zustand 01
下一篇
React白話文運動27-React Router 01
系列文
React框架白話文運動30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言